package com.xunk.equipment.service.ruying;

import com.xunk.common.core.exception.CustomException;
import com.xunk.common.core.utils.XunkAssert;
import com.xunk.equipment.domain.EquipmentDO;
import com.xunk.equipment.domain.EquipmentPropertiesData;
import com.xunk.equipment.service.BaseService;
import com.xunk.equipment.service.IWindowCurtainService;
import com.xunk.equipment.vo.response.WindowCurtainRresponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.xunk.common.core.domain.EquipmentResponse;

import java.util.*;

/**
 * @ProjectName: xunk
 * @Package: com.xunk.equipment.service.ruying
 * @ClassName: WindowCurtainService
 * @Author: tangguangyuan
 * @Description: 如影窗帘service
 * @Date: 2021/3/31 19:36
 * @Version: 1.0
 */

@Service("ruying-window-curtain")
public class WindowCurtainService implements IWindowCurtainService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    RuYingControlService ruYingControlService;

    @Autowired
    BaseService baseService;


    private static final String POSITION_ID = ".10.11";
    private static final String POSITION_STATUS_ID = ".10.12";
    private static final String TARGET_POSITION_ID = ".10.13";
    private static final String PROGRAM_MODE_ID = ".14.15";
    private static final String ON_ID = ".14.16";
    private static final String FIRMWARE_ID = ".1.2"; // 固件版本
    private static final String MODEL_ID = ".1.5"; //型号
    private static final String SERIALNUMBER_ID = ".1.7"; // 固件版本


    //操作开关 true-开  false-关
    public EquipmentPropertiesData setOn(String deviceId, Boolean value) {
        String pid = deviceId + ON_ID;

        //测试
        return createEquipmentPropertiesData(pid, value);
    }

    //操作目标位置 0-100 ,step : 5
    public EquipmentPropertiesData setTargetPosition(String deviceId, int value) {
        if (value % 5 != 0 || value < 0 || value > 100)
            throw new CustomException("目标位置非法");

        String pid = deviceId + TARGET_POSITION_ID;
        //测试
        return createEquipmentPropertiesData(pid, value);
    }

    //操作电机模式 0 1 2
    public EquipmentPropertiesData setProgramMode(String deviceId, int value) {
        if (value != 0 && value != 1 && value != 2)
            throw new CustomException("电机模式非法");
        String pid = deviceId + PROGRAM_MODE_ID;
        //测试
        return createEquipmentPropertiesData(pid, value);
    }


    /**
     * 设置多个属性，暂不用，后续如有需求再启用
     */
    /*public Boolean actions(String deviceId, String userId, Map<String,Object> map){
        EquipmentPropertiesData equipmentPropertiesData = new EquipmentPropertiesData();
        List<EquipmentPropertiesData.PropertyData> properties = new ArrayList<>();
        for (String action :
                map.keySet()) {
            switch (action){
                case "on":
                    properties.add(setOn(deviceId, Boolean.parseBoolean(map.get(action).toString())));
                    break;
                case "targetPosition":
                    properties.add(setTargetPosition(deviceId, Integer.parseInt(map.get(action).toString())));
                    break;
                case "mode":
                    properties.add(setProgramMode(deviceId, Integer.parseInt(map.get(action).toString())));
                    break;

                default:
                    throw new CustomException("窗帘控制指令非法");
            }
        }
        equipmentPropertiesData.setProperties(properties);
        return Objects.equals(ruYingControlService.setProperties(userId,equipmentPropertiesData),"success");
    }*/

    //获取窗帘所有属性
    @Override
    public EquipmentResponse getEquipmentInfo(EquipmentDO equipmentDO) {
        String deviceSn = equipmentDO.getDeviceSn();
        Long deptId = equipmentDO.getDeptId();
        Map<String, String> cacheMap = ruYingControlService.getShadowByDeviceSn(deviceSn, deptId);

        XunkAssert.notEmpty(cacheMap, String.format("设备%s属性不存在", deviceSn));

        WindowCurtainRresponse response = new WindowCurtainRresponse();

        int position = Integer.parseInt(cacheMap.getOrDefault(deviceSn.concat(POSITION_ID), "0"));

        int positionStatus = Integer.parseInt(cacheMap.getOrDefault(deviceSn.concat(POSITION_STATUS_ID), "0"));

        int targetPosition = Integer.parseInt(cacheMap.getOrDefault(deviceSn.concat(TARGET_POSITION_ID), "0"));

        int programMode = Integer.parseInt(cacheMap.getOrDefault(deviceSn.concat(PROGRAM_MODE_ID), "0"));

        Boolean on = Boolean.parseBoolean(cacheMap.getOrDefault(deviceSn.concat(ON_ID), "false"));

        String firmWare = Optional.ofNullable(cacheMap.get(deviceSn.concat(FIRMWARE_ID))).orElse("-");
        String model = Optional.ofNullable(cacheMap.get(deviceSn.concat(MODEL_ID))).orElse("-");
        String serialnumber = Optional.ofNullable(cacheMap.get(deviceSn.concat(SERIALNUMBER_ID))).orElse("-");

        response.setFirmWare(firmWare);
        response.setModel(model);
        response.setSerialNumber(serialnumber);
        response.setDeviceSn(deviceSn);
        response.setPosition(position);
        response.setPositionStatus(positionStatus);
        response.setTargetPosition(targetPosition);
        response.setProgramMode(programMode);
        response.setOn(on);
        response.setOnList(onList);
        response.setPositionRange(positionRange);
        response.setPositionStatusList(positionStatusList);
        response.setTargetPositionRange(targetPositionRange);
        response.setProgramModeList(programModeList);

        response.setSupplier(equipmentDO.getSupplier());
        response.setCandidateModel(baseService.getCandidateModel(equipmentDO.getDeviceBaseId()));
        return response;
    }

    // 开关预设值
    public List<Map<String, String>> onList = new ArrayList<Map<String, String>>(2) {{
        add(createMap("开", "true"));
        add(createMap("关", "false"));
    }};

    // 位置预设值
    public Map<String, String> positionRange = new HashMap<String, String>(2) {{
        put("min", "0");
        put("max", "100");
        put("step", "1");
    }};

    // 位置状态预设值
    public List<Map<String, String>> positionStatusList = new ArrayList<Map<String, String>>(2) {{
        add(createMap("朝最小值方向移动", "0"));
        add(createMap("朝最大值方向移动", "1"));
        add(createMap("停止", "2"));
    }};

    // 目标位置预设值
    public Map<String, String> targetPositionRange = new HashMap<String, String>() {{
        put("min", "0");
        put("max", "100");
        put("step", "5");
    }};

    // 电机模式
    public List<Map<String, String>> programModeList = new ArrayList<Map<String, String>>(2) {{
        add(createMap("Undefined", "0"));
        add(createMap("NoRevert", "1"));
        add(createMap("Revert", "2"));
    }};


    public Map<String, String> createMap(String key, String value) {
        Map<String, String> map = new HashMap<String, String>();
        map.put(key, value);
        return map;
    }

    //设置窗帘属性
    @Override
    public Boolean control(EquipmentDO equipmentDO, String type, String value) {

        String userId = baseService.findOwnIdByDeptId(equipmentDO.getDeptId());
        String deviceId = equipmentDO.getDeviceSn();
        EquipmentPropertiesData equipmentPropertiesData;
        switch (type) {
            case "on":
                equipmentPropertiesData = setOn(equipmentDO.getDeviceSn(), Boolean.parseBoolean(value));
                break;
            case "targetPosition":
                logger.info(String.format("窗帘：%s 位置设置为%s", deviceId, value));
                /**
                 * 窗帘位置为0时，先将位置设置为0，再将开关关闭
                 * 窗帘位置为非0时，先将开关打开，再设置位置
                 * */
                equipmentPropertiesData = setTargetPosition(deviceId, Integer.parseInt(value));
                return Objects.equals(ruYingControlService.setProperties(userId, equipmentPropertiesData), "success");
//                if (Integer.parseInt(value) != 0) {
//                    equipmentPropertiesData = setOn(deviceId, true);
//                    Boolean onResult = Objects.equals(ruYingControlService.setProperties(userId, equipmentPropertiesData), "success");
//                    if (onResult) {
//                        logger.info(String.format("窗帘:%s 打开成功", deviceId));
//                        equipmentPropertiesData = setTargetPosition(deviceId, Integer.parseInt(value));
//                        return Objects.equals(ruYingControlService.setProperties(userId, equipmentPropertiesData), "success");
//                    } else {
//                        logger.info(String.format("窗帘:%s 打开失败", deviceId));
//                        return false;
//                    }
//
//                } else {
//                    equipmentPropertiesData = setTargetPosition(deviceId, Integer.parseInt(value));
//                    Boolean onResult = Objects.equals(ruYingControlService.setProperties(userId, equipmentPropertiesData), "success");
//                    if (onResult) {
//                        logger.info(String.format("窗帘:%s 位置设置为0成功", deviceId));
//                        equipmentPropertiesData = setOn(deviceId, false);
//                        return Objects.equals(ruYingControlService.setProperties(userId, equipmentPropertiesData), "success");
//                    } else {
//                        logger.info(String.format("窗帘:%s 位置设置为0失败", deviceId));
//                        return false;
//                    }
//                }

            case "mode":
                equipmentPropertiesData = setProgramMode(deviceId, Integer.parseInt(value));
                break;
            default:
                throw new CustomException("控制指令非法");
        }

        return Objects.equals(ruYingControlService.setProperties(userId, equipmentPropertiesData), "success");
    }


    /**
     * 创建EquipmentPropertiesData
     */
    public EquipmentPropertiesData createEquipmentPropertiesData(String pid, Object value) {
        EquipmentPropertiesData equipmentPropertiesData = new EquipmentPropertiesData();
        List<EquipmentPropertiesData.PropertyData> propertyData = new ArrayList<EquipmentPropertiesData.PropertyData>(1) {{
            add(new EquipmentPropertiesData.PropertyData(pid, value));
        }};
        equipmentPropertiesData.setProperties(propertyData);
        //测试
        return equipmentPropertiesData;

    }
}
